#!/usr/bin/env python
"""
PyLink-SR (Python Linked Software Radio System)
(c) Bob Cowdery (G3UKB) 2008

File: app_headless.py
Date: December 2008

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

The author can be reached by email at

bob@g3ukb.co.uk

========================================================================
Module Description:

This is the start-up module of pylink hesdless main. This variant
permits another GUI implementation to be used.

To start the application (make it executable first):
Note, the parallel port requires sudo at present until I fix it in the C code?
To your .bashrc file in /home/yourusername add
export PYLINK_HOME="/home/bob/dev/pylink/" ; replace with your path
The -E tells sudo to pass the enviroment through else you won't get the PYLINK_HOME

>sudo -E ./app_headless.py

"""

#-----------------------------------------------------------------------
# System imports
import logging
import sys
import os
from time import sleep
import subprocess
from threading import Thread
import Pyro.core
from Pyro.EventService.Clients import Subscriber

# Set the PYTHONPATH
HOME = os.environ['PYLINK_HOME']
# Note that config_service.py and options.conf must live under $HOME/conf
sys.path.append(HOME + 'conf')
import config_service as config
config.open_config()
# Now we have the configuration loaded we can set the rest of PYTHONPATH
sys.path = sys.path + config.python_path().rsplit(',')
# ... before importing the rest of the modules
# Application imports
import logger_service as logger
import pyro_services

# Get the radio state database 
import radio_state.backdoor
radio_state.backdoor.setup_environ()
from admin.radio_state.models import State
        
state = {}

#======================================================================
# The main class of the application
class AppHeadless:
    def __init__(self):
        global glogger
        
        if config.mode() == 'standalone':
          # Start the Server process
          self.server = None
          self.server = subprocess.Popen(['python',config.server_path()])
          # Give it a chance to start
          sleep(10)
        
        Pyro.config.PYRO_HOST = config.pyro_local_host()
          
        # Start the DSP process
        self.dsp = None
        self.dsp = subprocess.Popen(['python',config.dsp_path()])
        # Give it a chance to start jack etc
        sleep(5)
         
        # Initialise the console components
        # Logging
        logger.init_logger()
        # Get our logger
        glogger = logging.getLogger('pylink.logger')
        
         # Get a hook into the event service
        self.es = Pyro.core.getProxyForURI("PYRONAME://"+Pyro.constants.EVENTSERVER_NAME)
        # Get our remote server
        self.server = Pyro.core.getProxyForURI("PYRONAME://servercontrol")
        
        # Start the UI process if required
        if config.ui_path():
            self.ui = None
            self.ui = subprocess.Popen(['python',config.ui_path()])
  
    #-----------------------------------------------------------------------
    # Send Ui Hints (on demand). Note, this will only be the initial state.
    def send_hints(self):
        global glogger
        # There is only one state object
        self.s = State.objects.get(pk=1)
        # Just dispatch the events
        self.es.publish('hw_events', ('set_freq', self.s.frequency))
        self.es.publish('dsp_events', ('set_mode', self.s.mode))
        self.es.publish('dsp_events', ('set_filter', self.s.filter))
        self.es.publish('dsp_events', ('set_agc', self.s.agc_state))
        self.es.publish('dsp_events', ('set_agc_rate', self.s.agc_rate))

    #-----------------------------------------------------------------------
    # Save the accumulated state
    def save_state(self):
        global glogger
        global state

        for key in state.keys():
          if key == 'frequency':
            self.s.frequency = state[key]
          elif key == 'mode':
            self.s.mode = state[key]
          elif key == 'filter':
            self.s.filter = state[key]
          elif key == 'agc_state':
            self.s.agc_state = state[key]
          elif key == 'agc_rate':
            self.s.agc_rate = state[key]
          self.s.save()

    #-----------------------------------------------------------------------
    # Abort signalled
    def abort(self):
        global glogger
        
        # Stop the controllers
        self.es.publish('hw_events', ('close_hw',None))
        self.es.publish('dsp_events', ('close_dsp',None))
        # Stop the pylink server
        self.server.close_and_exit()
        
    #-----------------------------------------------------------------------
    # Run the main headless process
    def run(self):
        global glogger
      
        Pyro.core.initServer()
        listener = UiHints(self)
        listener.subscribeMatch("ui_hints")
        glogger.info('PyLink-SR (Headless) listening..')
        listener.listen()
        glogger.info('PyLink-SR (Headless) listener exiting..')
   
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
class UiHints(Subscriber):
    global state
    
    #---------------------------------------------------------------------------
    def __init__(self, main):
        Subscriber.__init__(self)
        self.setThreading(0)
        self.main = main

    #---------------------------------------------------------------------------
    def event(self, event):
        # Wait for messages
        # Stash the hint     
        #print 'Headless received UI Hint', event.msg
        func, args = event.msg
        if func == 'do_hints':
            self.main.send_hints()
        elif func == 'terminate':
            self.main.save_state()
            self.main.abort()
            self.abort()
        elif func == 'freq_change':
            state['frequency'] = args
        elif func == 'mode':
            state['mode'] = args
        elif func == 'filter':
            state['filter'] = args
        elif func == 'agc_hints':
            what, value = args
            if what == 'state':
                state['agc_state'] = value
            elif what == 'rate':
                state['agc_rate'] = value
        
#--------------------------------------------------------------------------
#
# Start from the command line
#
if __name__ == "__main__":
  global glogger
  
  app = AppHeadless()
  
  # Start the main loop
  glogger.info("PyLink-SR (Headless) running..")
  app.run()
  
  # Announce we are going 
  glogger.info("PyLink-SR (Headless) closing..")
  

